 /*	
 *				
 *					ISNW ---- It is a war.It is not warcraft!
 *
 *
 *					Author:					zhoukeli(haxixi_keli)
 *					Filename:				XMeshLoader.h
 *					CreateTime:				2008/12/14
 *					ModifyTime:				2008/12/14
 *					ModifyTime:				2008/12/19
 *					ModifyTime:				2008/12/20
 *
 */

#ifndef __ISNW_XMESH_LOADER_H__
#define __ISNW_XMESH_LOADER_H__

#include "include/IMeshLoader.h"
#include "include/IAnimateMesh.h"
#include "include/isnwArray.h"
#include "include/isnwVertex.h"
#include "include/vector3d.h"
#include "include/isnwMaterial.h"
#include "SkinnedMesh.h"

namespace ISNW
{
namespace scene
{
	class XMeshLoader : public IMeshLoader
	{
	public:
		enum E_X_LEX
		{
			UNKNOWN,					// unknown,error

			COMMENT,					// comment: // or #
			BLOCKBEGIN,					// {
			BLOCKEND,					// }
			SBLOCKBEGIN,				// [
			SBLOCKEND,					// ]
			NAME,						// some name
			NUMBER,						// int or float
			STRING,						// "string"

			TEMPLATE,					// template
			FRAME,						// frame
			FRAMETRANSFORMMATRIX,		// frame transform matrix

			MESH,						// mesh
			MESHNORMALS,				// meshnormals
			MESHTEXTURECOORDS,			// mesh texture coords
			MESHVERTEXCOLORS,			// mesh vertex colors
			MESHMATERIALLIST,			// mesh material list
			VERTEXDUPLICATIONINDICES,	// vertex duplication indices
			XSKINMESHHEADER,			// x skin mesh header
			SKINWEIGHTS,					// skin weight

			MATERIAL,					// material
			TEXTUREFILENAME,			// texture file name

			ANIMATIONSET,				// animation set
			ANIMATION,					// animation
			ANIMATIONKEY,				// animation key
			ANIMATIONOPTIONS,			// animation option

			UUID,						// uuid

			SEMICOLON,					// ;
			COMMA,						// ,


			ENDOFILE,					// end of file
		};

	public:
		XMeshLoader();
		~XMeshLoader();

	public:
		bool isLoaderableFile(const c8* filename) const;

		IAnimateMesh* createmesh(io::IReadFile* file);

		struct XMesh
		{
			//! mesh has a name
			core::string					name;

			//! index , each face composites of 3 index
			core::array<u16>				indices;

			core::array<u16>				indexcountperface;

			//! vertex
			core::array<video::vertex>		vertices;

			//! material
			core::array<u16>				facematerialidx;

			core::array<video::material>	matierals;

			//! X skin
			u32							nMaxSkinWeightsPerVertex;
			u32							nMaxSkinWeightsPerFace;
			u32							nBones;

			//! attach to joint,(-1 indicates it has no attached joint)
			s32								attachedjointid;

			//! mesh buffer,for optimize
			core::array<scene::MeshBuffer*>	buffers;

			//! attached weight
			core::array<u32> weight_joint;
			core::array<u32> weight_joint_weight;

			XMesh()
				:attachedjointid(0)
				,nMaxSkinWeightsPerFace(0)
				,nMaxSkinWeightsPerVertex(0)
				,nBones(0){}
			
		};

	protected:
		//! load whole content into memory
		bool load(io::IReadFile* file);

		//! parse the x file
		bool parse();

		//! parse template <template-name>{
		//			<UUID>
		//			<member1>
		//			<member2>
		//			.........
		//			[restrictions]
		//		   }
		bool parse_template();

		//! parse frame
		//			frame <frame-name>{
		//				[...]
		//			}
		bool parse_frame(SkinnedMesh::joint* parent);

		//! parse frame transform matrix
		bool parse_frametransformmatrix(SkinnedMesh::joint* frame);

		//! parse mesh
		//			mesh <mesh-name>{
		//				<UUID>
		//				DWORD nVertices;
		//				array vector vertices[nVertices];
		//				DWORD nFaces;
		//				array meshface faces[nFaces];
		//				[...]
		//			}
		bool parse_mesh(XMesh* mesh);

		//! parse meshnormals
		//			meshnormals <meshnormals-name>{
		//				<UUID>
		//				DWORD nNormals;
		//				array vector normals[nNormals];
		//				DWORD nFaces;
		//				array meshface faces[nNormals];
		//			}
		bool parse_meshnormals(XMesh* mesh);

		//! parse meshtexturecoords
		//			meshtexturecoords <name>{
		//				<UUID>
		//				DWORD nTextureCoords;
		//				array Coords2d textureCoords[nTextureCoords];
		//			}
		bool parse_meshtexturecoords(XMesh* mesh);

		//! parse mesh vertex colors
		bool parse_meshvertexcolors(XMesh* mesh);

		//! parse animationset
		bool parse_animationset();

		//! parse animation
		bool parse_animation();

		//! parse animationkey
		bool parse_animationkey(SkinnedMesh::joint* j);

		//! parse animation option
		bool parse_animationoption();

		//! parse mesh material list
		bool parse_meshmateriallist(XMesh* mesh);

		//! parse material
		bool parse_material(video::material& m);

		//! parse texture file name
		bool parse_texturefilename(core::string& out);

		//! parse skin weights
		bool parse_skinweights(XMesh* mesh);

		//! parse x skin mesh header
		bool parse_xskinmeshheader(XMesh* mesh);

		//! read DWORD
		bool readword(u32& out);

		//! read float
		bool readfloat(f32& out);

		//! read float vector3d
		bool readvectorf3d(core::vector3df& out);

		//! read float vector2d
		bool readvectorf2d(core::vector2df& out);

		//! read color RGBA
		bool readcolorRGBA(video::color32& out);

		//! read color RGB
		bool readcolorRGB(video::color32& out);

		//! read matrix 4*4
		bool readmatrix4f(core::matrix4f& out);

		//! get next lexeme
		E_X_LEX nextlex();

		E_X_LEX lex();

		//! get char and next
		c8 char_next();

		//! get current char
		c8 currchar();

		//! just skip current char
		void next();

		//! check next char
		bool check(u8);

		//! check and skip if true
		bool check_next(u8);

		//! skip comment line
		bool skipcomment();

		//! skip after /r /n
		bool skipaline();

		//! skip space
		bool skipspace();

		//! skip /r /n
		bool skiprn();

		//! skip {..}
		bool skipblock();

		//! curr == end?
		bool isend() const;

		//! read string
		bool readstring(core::string&);

		//! read "string"
		bool readquotastring(core::string&);

		//! read uuid
		bool readuuid();

	protected:
		s32 MajorVersion;
		s32 MinorVersion;

		bool istxtformat;
		s32 bits4float;

		c8* buffer;
		c8* curr;
		c8* end;
		s32 size;

		SkinnedMesh* AnimateMesh;

		core::array<XMesh*> meshes;

		core::string curr_lex_as_string;
	};
} // end namespace scene
} // end namespace ISNW
#endif